package locker

import (
	"bytes"
	"log"
	"net"
	"strings"
	"sync/atomic"
	"time"
)


type Server interface {
	Start(addr string) error
	Stop() bool
}

const (
	DELIM = '\n' // 分隔符。
)

type myServer struct {
	locker   Locker
	status   uint32
	listener net.Listener
}

func (this *myServer) Start(addr string) error {
	if !atomic.CompareAndSwapUint32(&this.status, 0, 1) {
		return nil
	}
	ls, err := net.Listen("tcp", addr)
	if err != nil {
		atomic.CompareAndSwapUint32(&this.status, 1, 0)
		return err
	}
	this.listener = ls
	go func() {
		c := time.Tick(time.Second)
		for _ = range c{
			this.locker.Free()
		}
	}()
	for {
		if atomic.LoadUint32(&this.status) != 1 {
			break
		}
		accept, err := this.listener.Accept()
		if err != nil {
			if atomic.LoadUint32(&this.status) == 1 {
				log.Printf("accept err with %v", err)
			} else {
				log.Println("server is closed")
			}
			continue
		}
		go this.handReq(accept)
	}
	return nil
}
func (this *myServer) handReq(con net.Conn) {
	defer con.Close()
	var buffer bytes.Buffer
	readByte := make([]byte, 1)
	var le uint32 = 0
	var errmsg string
	for {
		if le > 100 {
			errmsg = "data is to big"
			break
		}
		_, err := con.Read(readByte)
		if err != nil {
			errmsg = "read err "
			log.Printf("read con err %v", err)
			break
		}
		if readByte[0] == DELIM {
			str := buffer.String()
			s := strings.Split(str, " ")
			le = 0
			buffer.Reset()
			if len(s) <= 1 {
				errmsg = "params is err "
				break
			}
			command := strings.Trim(s[0], " ")
			key := strings.Trim(s[1], " ")
			if command!= "lock" && command !="unlock"{
				errmsg = "command is err "
				break;
			}
			var rs bool
			if command == "lock"{
				rs = this.locker.Lock(key,false)
			}else {
				rs = this.locker.Unlock(key)
			}
			if rs {
				con.Write(([]byte)("ok"))
			} else {
				con.Write(([]byte)("fail"))
			}
			continue
		}
		le++
		buffer.Write(readByte)
	}

	if errmsg != "" {
		con.Write(([]byte)(errmsg))
	}
}
func (this *myServer) Stop() bool {
	return true
}
func NewServer() Server {
	server := &myServer{}
	server.locker = NewLocker()
	return server
}
